﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using Fcdbas.Core.WCF.TransFile.Client.Handlers;
using Fcdbas.Core.WCF.TransFile.Client;
using Fcdbas.Core.WCF.TransFile.Contracts.Services;
using Fcdbas.Core.WCF.TransFile.Channels;
using Fcdbas.Core.WCF.TransFile.Contracts.Models;
using Fcdbas.Core.WCF.TransFile.Contracts.Enums;
using System.Threading;
using System.IO;

namespace Fcdbas.Core.WCF.TransFile.Client
{
    ///<summary>
    ///时间:   2011-09-15
    ///描述:   文件加载工作单元
    ///<summary>
    public class UpLoadFileWorker : IDisposable
    {

        #region ====================================  构造函数 ====================================

        public UpLoadFileWorker()
        {
            initUpLoadWorkerItem();
        }

        #endregion

        #region ====================================  私有字段 ====================================

        /// <summary>
        /// 工作单元标识
        /// </summary>
        private bool _WorkerFlag = true;

        /// <summary>
        /// 后台工作单元
        /// </summary>
        private BackgroundWorker _UpLoadWorkerItem;

        /// <summary>
        /// 备份文件名称
        /// </summary>
        private string _BackupFileName = string.Empty;

        /// <summary>
        /// 偏移量
        /// </summary>
        private long _OffSet = 0;

        /// <summary>
        /// 增量大小
        /// </summary>
        private long _IncrementSize = 512 * 1024;


        private UpLoadFileInfo _UpLoadInfo;


        #endregion

        #region ====================================  公共属性 ====================================

        /// <summary>
        /// 增量大小
        /// </summary>
        public long IncrementSize
        {
            get { return _IncrementSize; }
            set { _IncrementSize = value; }
        }

        #endregion

        #region ====================================  公共事件 ====================================

        /// <summary>
        /// 上传事件
        /// </summary>
        public event FileLoadEventHandler UpLoadEvent;

        #endregion

        #region ====================================  私有方法 ====================================

        /// <summary>
        /// 初始化后台工作单元
        /// </summary>
        private void initUpLoadWorkerItem()
        {
            _UpLoadWorkerItem = new BackgroundWorker();
            _UpLoadWorkerItem.DoWork += new DoWorkEventHandler(_WorkerItem_DoWork);
        }

        /// <summary>
        /// 后台工作内容
        /// </summary>
        private void _WorkerItem_DoWork(object sender, DoWorkEventArgs e)
        {
            UpLoadFileInfo info = e.Argument as UpLoadFileInfo;
            if (info != null)
            {
                FileLoadEventArgs args = new FileLoadEventArgs();

                IFileService provider = ChannelContainer.GetChannel<IFileService>("IFileService");

                LoadFileInfoModel loadInfo = new LoadFileInfoModel();
                loadInfo.FileTitle = info.FileTitle;
                loadInfo.FileSize = info.FileSize;
                loadInfo.Extension = info.Extension;
                loadInfo.CustomFolder = info.CustomFolder;
                loadInfo.UpLoadFileType = info.SpaceType;
                loadInfo.IsClientBuilderPath = info.IsClientBuilderPath;
                loadInfo.ClientBuilderPath = info.ClientBuilderPath;
                args.Size = (int)info.FileSize;
                bool beContinue = false;
                bool isBackup = false;
                if (info.ToolType == ToolType.Start || info.ToolType == ToolType.ReStart)
                {
                    args.Progress = LoadProgress.CheckeFile;
                    OnUpLoadEvent(args);
                    CheckFileResult chResult = provider.CheckFile(loadInfo);
                    beContinue = chResult.IsSuccess;
                    isBackup = chResult.IsBackup;
                    if (chResult.IsBackup)
                    {
                        _BackupFileName = chResult.BackupFileName;
                    }
                    _OffSet = 0;
                }
                else if (info.ToolType == ToolType.Continue)
                {
                    args.Progress = LoadProgress.GetOffSet;
                    OnUpLoadEvent(args);
                    GetOffSetResult getResult = provider.GetFileOffSet(loadInfo, true);
                    if (getResult.IsSuccess && getResult.OffSet > -1)
                    {
                        beContinue = true;
                        _OffSet = getResult.OffSet;
                    }
                    else
                    {
                        _OffSet = 0;
                    }
                }
                else if (info.ToolType == ToolType.Delete)
                {
                    beContinue = false;
                    args.Progress = LoadProgress.DeleteFile;
                    OnUpLoadEvent(args);

                    loadInfo.IncrementData = null;
                    CheckFileResult result = provider.DeleteFile(loadInfo);
                    args.Progress = result.IsSuccess ? LoadProgress.DeleteSuccess : LoadProgress.DeleteFail;
                    OnUpLoadEvent(args);
                    goto Stop;
                }

                if (beContinue)
                {

                    //if (_FileStream == null)
                    //{
                    //    args.Progress = LoadProgress.ReadLocalFile;
                    //    OnUpLoadEvent(args);
                    //    beContinue = ReadFileToMemory(info.LocalPath);
                    //    args.Progress = beContinue ? LoadProgress.ReadLocalSuccess : LoadProgress.ReadLocalFail;
                    //    OnUpLoadEvent(args);
                    //}

                    args.Progress = LoadProgress.Begin;
                    OnUpLoadEvent(args);
                    loadInfo.OffsetIndex = _OffSet;
                    int errorCount = 0;
                    while (_OffSet < _UpLoadInfo.FileSize)
                    {
                        if (!_WorkerFlag)
                        {
                            goto Stop;
                        }
                        try
                        {
                            byte[] temp;
                            ///判断断点位置
                            long currentIncurementSize = _UpLoadInfo.FileSize - loadInfo.OffsetIndex >= _IncrementSize ? _IncrementSize : _UpLoadInfo.FileSize - _OffSet;

                            ///获取增量内容
                            //_FileStream.Seek(loadInfo.OffsetIndex, SeekOrigin.Begin);
                            //_FileStream.Read(temp, 0, temp.Length);

                            ///设置上传属性
                            loadInfo.IncrementSize = currentIncurementSize;
                            loadInfo.IncrementData = ReadLocalBuffer(_OffSet, currentIncurementSize);


                            ///调用上传方法
                            loadInfo = provider.UpLoadFile(loadInfo);

                            ///通知UI
                            args.Current = (int)loadInfo.OffsetIndex;
                            args.Progress = LoadProgress.Loading;

                            args.ResultType = loadInfo.Result;
                            OnUpLoadEvent(args);
                            temp = null;
                            _OffSet = loadInfo.OffsetIndex;
                            loadInfo.IncrementData = null;
                            GC.Collect();

                        }
                        catch (Exception ex)
                        {
                            loadInfo.IncrementData = null;
                            GC.Collect();

                            ///允许上传失败 5次
                            errorCount++;
                            if (errorCount == 5)
                            {
                                args.Progress = LoadProgress.Error;
                                OnUpLoadEvent(args);
                                break;
                            }
                        }
                    }

                    ///删除备份
                    if (isBackup)
                    {
                        try
                        {
                            args.Progress = LoadProgress.DeleteBackup;
                            OnUpLoadEvent(args);

                            loadInfo.IncrementData = null;
                            loadInfo.FileTitle = _BackupFileName;
                            CheckFileResult result = provider.DeleteFile(loadInfo);
                            args.Progress = result.IsSuccess ? LoadProgress.DeleteSuccess : LoadProgress.DeleteFail;
                            OnUpLoadEvent(args);
                        }
                        catch { }
                    }

                    if (_OffSet > 0 && _OffSet == info.FileSize)
                    {
                        args.Progress = LoadProgress.Complete;
                        OnUpLoadEvent(args);
                    }
                }

            Stop:
                string empty = string.Empty;
            }
        }

        /// <summary>
        /// 工作时间触发器
        /// </summary>
        private void OnUpLoadEvent(FileLoadEventArgs e)
        {
            if (UpLoadEvent != null)
            {
                UpLoadEvent(e.Clone());
            }
        }

        /// <summary>
        /// 开始工作单元
        /// </summary>
        private void BeginWorker(UpLoadFileInfo info)
        {
            while (_WorkerFlag)
            {
                if (_UpLoadWorkerItem != null && !_UpLoadWorkerItem.IsBusy)
                {
                    _UpLoadWorkerItem.RunWorkerAsync(info);
                    break;
                }
                Thread.Sleep(300);
            }
        }

        /// <summary>
        /// 读取本地文件
        /// </summary>
        /// <param name="offset">偏移量</param>
        /// <param name="length">读取长度</param>
        /// <returns></returns>
        private byte[] ReadLocalBuffer(long offset, long length)
        {
            byte[] temp;
            try
            {
                temp = new byte[length];
                ///读取本地文件到内存
                using (FileStream fileStream = new FileStream(_UpLoadInfo.LocalPath, FileMode.Open, FileAccess.ReadWrite))
                {
                    fileStream.Seek(offset, SeekOrigin.Current);
                    fileStream.Read(temp, 0, temp.Length);
                    fileStream.Flush();
                }
                GC.Collect();
            }
            catch (Exception ex)
            {
                temp = null;
            }
            return temp;
        }

        #endregion

        #region ====================================  公共方法 ====================================


        /// <summary>
        /// 启动上传
        /// </summary>
        /// <param name="info">上传内容</param>
        public void Start(UpLoadFileInfo info)
        {
            info.ToolType = ToolType.Start;
            _UpLoadInfo = info;
            _WorkerFlag = true;
            BeginWorker(info);
        }

        /// <summary>
        /// 重新启动上传
        /// </summary>
        public void ReStart()
        {
            _UpLoadInfo.ToolType = ToolType.ReStart;
            _WorkerFlag = true;
            BeginWorker(_UpLoadInfo);
        }

        /// <summary>
        /// 继续上传
        /// </summary>
        public void Continue()
        {
            _UpLoadInfo.ToolType = ToolType.Continue;
            _WorkerFlag = true;
            BeginWorker(_UpLoadInfo);
        }

        /// <summary>
        /// 停止上传
        /// </summary>
        public void Stop()
        {
            _WorkerFlag = false;
            Thread.Sleep(100);
        }

        /// <summary>
        /// 删除上传
        /// </summary>
        public void Delete()
        {
            _UpLoadInfo.ToolType = ToolType.Delete;
            _WorkerFlag = true;
            BeginWorker(_UpLoadInfo);
        }

        /// <summary>
        /// 销毁
        /// </summary>
        public void Dispose()
        {
            _WorkerFlag = false;

            Thread.Sleep(100);
            if (_UpLoadWorkerItem != null)
                _UpLoadWorkerItem.Dispose();
            GC.Collect();
        }

        #endregion
    }
}
